import grpcWeb from 'grpc-web';
import { string2Uint8Array } from '@/utils';
import { LicenseServiceClient } from './LicenseServiceClientPb';
import { LicenseRequest, LicenseResponse, LicenseVersion } from './license_pb';

interface ClientOption {
  /**
   * @description 协议模式
   * @default http
   */
  schema?: string;
  /**
   * @description 服务端主机
   * @default localhost
   */
  host?: string;
  /**
   * @description 服务端端口
   * @default 50051
   */
  port?: number;
  metadata?: grpcWeb.Metadata;
}

export type Request = LicenseRequest.AsObject;

export type Response = LicenseResponse.AsObject;

class Client {
  private serviceClient: LicenseServiceClient;

  private schema: string;

  private host: string;

  private port: number;

  private metadata: grpcWeb.Metadata;

  constructor(opts?: ClientOption) {
    this.init(opts);
  }

  private init(opts?: ClientOption) {
    const { schema, host, port, metadata } = opts || {};
    this.schema = schema || 'http';
    this.host = host || 'localhost';
    this.port = port || 50051;
    this.metadata = metadata || null;
    const hostname = `${this.schema}://${this.host}:${this.port}`;
    if (this.serviceClient != null) {
      this.serviceClient = null;
    }
    this.serviceClient = new LicenseServiceClient(hostname, null, null);
  }

  config(opts?: ClientOption) {
    this.init(opts);
  }

  async send(request: Request): Promise<Response> {
    const req = new LicenseRequest();
    const { registrationInformation, accessToken, version, options, username, password } = request;
    if (version) {
      req.setVersion(version);
    } else {
      const { version } = options || {};
      switch (version) {
        case '8.0':
          req.setVersion(LicenseVersion.F8);
          break;
        case '9.0':
          req.setVersion(LicenseVersion.F9);
          break;
        case '10.0':
        default:
          req.setVersion(LicenseVersion.F10);
      }
    }
    if (registrationInformation) {
      if (typeof registrationInformation === 'string') {
        req.setRegistrationInformation(string2Uint8Array(registrationInformation));
      }
      req.setRegistrationInformation(registrationInformation);
    }

    if (accessToken) {
      req.setAccessToken(accessToken);
    }

    // todo Request => LicenseRequest
    const res = await this.serviceClient.grant(req, this.metadata);
    return res.toObject();
  }
}

export default Client;
